#!/usr/bin/env python3


import argparse
import copy
import json
import os
import jsonschema
import yaml


ROOT = os.environ.get("ROOT", os.getcwd())


def get_args():
    """
    Returns arguments from the command line
    """

    parser = argparse.ArgumentParser()
    parser.add_argument("service_dir")
    parser.add_argument("artifacts_dir")
    return parser.parse_args()


def get_environments(has_env: bool = True) -> dict:
    """
    Retrieve all environments
    """

    # Load and validate environments.yaml
    schema_file = os.path.join(ROOT, "shared", "environments", "schema.yaml")
    environments_file = os.path.join(ROOT, "environments.yaml")

    if not os.path.isfile(environments_file):
        raise ValueError("Missing environments file '{}'".format(environments_file))

    with open(schema_file) as fp:
        schema = yaml.load(fp, Loader=yaml.SafeLoader)
    
    with open(environments_file) as fp:
        environments = yaml.load(fp, Loader=yaml.SafeLoader)

    jsonschema.validate(environments, schema)

    # For services that don't support environments, default to prod settings
    if not has_env:
        environment = environments.get("prod", {})
        environment["environment"] = ""
        return {"": environment}

    # Inject the 'environment' key
    for key, environment in environments.items():
        environment["environment"] = key

    # Return all environments
    return environments


def get_metadata(service_dir: str) -> dict:
    """
    Retrieve metadata for the service
    """

    # Load and validate service_dir/metadata.yaml
    schema_file = os.path.join(ROOT, "shared", "metadata", "schema.yaml")
    metadata_file = os.path.join(service_dir, "metadata.yaml")

    if not os.path.isfile(metadata_file):
        raise ValueError("Missing metadata file '{}'".format(metadata_file))

    with open(schema_file) as fp:
        schema = yaml.load(fp, Loader=yaml.SafeLoader)
    
    with open(metadata_file) as fp:
        metadata = yaml.load(fp, Loader=yaml.SafeLoader)

    jsonschema.validate(metadata, schema)

    return metadata


def get_parameters(metadata: dict, environment: dict) -> dict:
    """
    Return parameters based on the environment and metadata
    """

    base_params = {
        "Environment": environment["environment"] or "prod"
    }

    for key, value in environment.get("parameters", {}).items():
        if isinstance(value, str):
            base_params[key] = value.format(**base_params)
        else:
            base_params[key] = value

    parameters = copy.deepcopy(base_params)

    for key, value in metadata.get("parameters", {}).items():
        if isinstance(value, str):
            parameters[key] = value.format(**base_params)
        else:
            parameters[key] = value

    return parameters

def get_tags(metadata: dict, environment: dict) -> dict:
    """
    Returns tags based on the environment and metadata
    """

    base_tags = {
        "Domain": os.environ.get("DOMAIN", "ecommerce"),
        "Service": metadata["name"],
        "Environment": environment["environment"] or "prod"
    }

    for key, value in environment.get("tags", {}).items():
        if isinstance(value, str):
            base_tags[key] = value.format(**base_tags)
        else:
            base_tags[key] = value

    tags = copy.deepcopy(base_tags)

    for key, value in metadata.get("tags", {}).items():
        if isinstance(value, str):
            tags[key] = value.format(**base_tags)
        else:
            tags[key] = value

    return tags


def main(service_dir: str, artifacts_dir: str):
    """
    Build artifacts from the service directory
    """

    metadata = get_metadata(service_dir)
    environments = get_environments(metadata.get("flags", {}).get("environments", True))

    for env_name, environment in environments.items():
        tags = get_tags(metadata, environment)
        parameters = get_parameters(metadata, environment)

        config = {
            "Parameters": parameters,
            "Tags": tags
        }

        artifact_file = os.path.join(artifacts_dir, "config.{}.json".format(env_name))
        with open(artifact_file, "w") as fp:
            json.dump(config, fp, indent=2)


if __name__ == "__main__":
    args = get_args()
    main(args.service_dir, args.artifacts_dir)